home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet internetowy / Rozne / HTTrack 3.40-2 / httrack-3.40-2.exe / {app} / src / htsftp.c < prev    next >
C/C++ Source or Header  |  2006-01-21  |  34KB  |  1,154 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: basic FTP protocol manager                             */
  34. /* Author: Xavier Roche                                         */
  35. /* ------------------------------------------------------------ */
  36.  
  37. /* Internal engine bytecode */
  38. #define HTS_INTERNAL_BYTECODE
  39.  
  40. // Gestion protocole ftp
  41. // Version .05 (01/2000)
  42.  
  43. #include "htsftp.h"
  44.  
  45. #include "htsglobal.h"
  46. #include "htsbase.h"
  47. #include "htsnet.h"
  48. #include "htsthread.h"
  49. #if HTS_WIN
  50. #else
  51. //inet_ntoa
  52. #include <arpa/inet.h>
  53. #endif
  54.  
  55. #if HTS_WIN
  56. #ifndef __cplusplus
  57. // DOS
  58. #ifndef  _WIN32_WCE
  59. #include <process.h>    /* _beginthread, _endthread */
  60. #endif
  61. #endif
  62. #endif
  63.  
  64. // ftp mode passif
  65. // #if HTS_INET6==0
  66. #define FTP_PASV 1
  67. // #else
  68. // no passive mode for v6
  69. // #define FTP_PASV 0
  70. // #endif
  71.  
  72. #define FTP_DEBUG 0
  73. //#define FORK_DEBUG 0
  74.  
  75. #define FTP_STATUS_READY 1001
  76.  
  77. #if USE_BEGINTHREAD
  78.  
  79. PTHREAD_TYPE PTHREAD_TYPE_FNC back_launch_ftp( void* pP ) {
  80.   lien_back* back=(lien_back*) pP;
  81.   if (back == NULL) {
  82. #if FTP_DEBUG
  83.     printf("[ftp error: no args]\n");
  84. #endif
  85.     return PTHREAD_RETURN;
  86.   }
  87.  
  88.   /* Initialize */ 
  89.   hts_init();
  90.  
  91.   // lancer ftp
  92. #if FTP_DEBUG
  93.   printf("[Launching main ftp routine]\n");
  94. #endif
  95.   run_launch_ftp(back);
  96.   // prΩt
  97.   back->status=FTP_STATUS_READY;
  98.   
  99.   /* Uninitialize */
  100.   hts_uninit();
  101.   return PTHREAD_RETURN;
  102. }
  103. // lancer en back
  104. void launch_ftp(lien_back* back) {
  105.   // DOS
  106. #if FTP_DEBUG
  107.   printf("[Launching main ftp thread]\n");
  108. #endif
  109.   (void)hts_newthread(back_launch_ftp, 0, (void*) back);
  110. }
  111.  
  112. #else
  113. // Unix sans pthread
  114. int back_launch_ftp(lien_back* back) {
  115.   // lancer ftp
  116.   run_launch_ftp(back);
  117.   // prΩt
  118.   back->status=FTP_STATUS_READY;
  119.   return 0;
  120. }
  121. void launch_ftp(lien_back* back,char* path,char* exec) {
  122.   FILE* fp = fopen(fconv(path),"wb");
  123.   if (fp) {
  124.     char _args[8][256];
  125.     char *args[8];
  126.     fclose(fp); fp=NULL;
  127.     
  128.     strcpybuff(_args[0],exec);
  129.     strcpybuff(_args[1],"-#R");
  130.     strcpybuff(_args[2],back->url_adr);
  131.     strcpybuff(_args[3],back->url_fil);
  132.     strcpybuff(_args[4],back->url_sav);
  133.     strcpybuff(_args[5],path);
  134.     //strcpybuff(_args[6],"");
  135.     args[0]=_args[0];
  136.     args[1]=_args[1];
  137.     args[2]=_args[2];
  138.     args[3]=_args[3];
  139.     args[4]=_args[4];
  140.     args[5]=_args[5];
  141.     args[6]=NULL;
  142.     switch (fork()) {    // note: vfork dΘconne un max'
  143.     case -1: printf("Can not vfork() process\n"); break;
  144.     case 0: 
  145.       if (execvp(args[0],args)==-1) {
  146.         fp=fopen(fconv(path),"wb");
  147.         if (fp) {
  148.           fprintf(fp,"-1 unable to launch %s",args[0]);
  149.           fclose(fp); fp=NULL;
  150.           rename(path,concat(path,".ok"));
  151.         } else remove(path);
  152.       }
  153.       _exit(0);    // exit 'propre'
  154.       break;
  155.     default:  // parent
  156.       // bah on fait rien..
  157.       break;         
  158.     }
  159.   }
  160. }
  161. #endif
  162.  
  163. // pour l'arrΩt du ftp
  164. #ifdef _WIN32
  165. #define _T_SOC_close(soc)  closesocket(soc); soc=INVALID_SOCKET;
  166. #else
  167. #define _T_SOC_close(soc)  close(soc); soc=INVALID_SOCKET;
  168. #endif
  169. #define _HALT_FTP { \
  170.   if ( soc_ctl     != INVALID_SOCKET ) _T_SOC_close(soc_ctl); \
  171.   if ( soc_servdat != INVALID_SOCKET ) _T_SOC_close(soc_servdat); \
  172.   if ( soc_dat     != INVALID_SOCKET ) _T_SOC_close(soc_dat); \
  173. }
  174. #define _CHECK_HALT_FTP \
  175.   if (stop_ftp(back)) { \
  176.   _HALT_FTP \
  177.   return 0; \
  178.   }
  179.  
  180. // la vΘritable fonction une fois lancΘes les routines thread/fork
  181. int run_launch_ftp(lien_back* back) {
  182.   char user[256]="anonymous";
  183.   char pass[256]="user@";
  184.   char line_retr[2048];
  185.   int port=21;
  186. #if FTP_PASV
  187.   int port_pasv=0;
  188. #endif
  189.   char BIGSTK adr_ip[1024];
  190.   char *adr,*real_adr;
  191.   char* ftp_filename="";
  192.   int timeout = 300;    // timeout
  193.   int timeout_onfly=8;  // attente rΘponse supplΘmentaire
  194.   int transfer_list=0;  // directory
  195.   int rest_understood=0;  // rest command understood
  196.   t_fullhostent fullhostent_buffer;   // buffer pour resolver
  197.   //
  198.   T_SOC soc_ctl=INVALID_SOCKET;
  199.   T_SOC soc_servdat=INVALID_SOCKET;
  200.   T_SOC soc_dat=INVALID_SOCKET;
  201.   //
  202.   SOCaddr server_data;
  203.   int server_data_size=sizeof(server_data);
  204.   //
  205.   line_retr[0]=adr_ip[0]='\0';
  206.   
  207.   timeout=300;
  208.   
  209.   // effacer
  210.   strcpybuff(back->r.msg,"");
  211.   back->r.statuscode=0;
  212.   back->r.size=0;
  213.   
  214.   // rΘcupΘrer user et pass si prΘsents, et sauter user:id@ dans adr
  215.   real_adr = strchr(back->url_adr,':');
  216.   if (real_adr) real_adr++;
  217.   else real_adr=back->url_adr;
  218.   while(*real_adr=='/') real_adr++;    // sauter /
  219.   if ( (adr = jump_identification(real_adr)) != real_adr) {  // user
  220.     int i=-1;
  221.     pass[0]='\0';
  222.     do {
  223.       i++;
  224.       user[i]=real_adr[i];
  225.     } while( (real_adr[i]!=':') && (real_adr[i]) );
  226.     user[i]='\0';
  227.     if (real_adr[i]==':') {    // pass
  228.       int j=-1;
  229.       i++;  // oui on saute aussi le :
  230.       do {
  231.         j++;
  232.         pass[j]=real_adr[i+j];
  233.       } while( ((&real_adr[i+j+1]) < adr) && (real_adr[i+j]) );
  234.       pass[j]='\0';
  235.     }
  236.   }
  237.   
  238.   // Calculer RETR <nom>
  239.   {
  240.     char* a;
  241. #if 0
  242.     a=back->url_fil + strlen(back->url_fil)-1;
  243.     while( (a > back->url_fil) && (*a!='/')) a--;
  244.     if (*a != '/') {
  245.       a = NULL;
  246.     }
  247. #else
  248.     a = back->url_fil;
  249. #endif
  250.     if (a != NULL && *a != '\0') {
  251. #if 0
  252.       a++;    // sauter /
  253. #endif
  254.       ftp_filename=a;
  255.       if (strnotempty(a)) {
  256.         char* ua=unescape_http(a);
  257.         int len_a = (int) strlen(ua);
  258.         if (len_a > 0 && ua[len_a -1] == '/') {     /* obviously a directory listing */
  259.           transfer_list=1;
  260.           sprintf(line_retr,"LIST -A %s",ua);
  261.         } else if (
  262.           (strchr(ua, ' '))
  263.           ||
  264.           (strchr(ua, '\"'))
  265.           ||
  266.           (strchr(ua, '\''))
  267.           ) {
  268.           sprintf(line_retr,"RETR \"%s\"",ua);
  269.         } else {      /* Regular one */
  270.           sprintf(line_retr,"RETR %s",ua);
  271.         }
  272.       } else {
  273.         transfer_list=1;
  274.         sprintf(line_retr,"LIST -A");
  275.       }
  276.     } else {
  277.       strcpybuff(back->r.msg,"Unexpected PORT error");
  278.       // back->status=FTP_STATUS_READY;    // fini
  279.       back->r.statuscode=STATUSCODE_INVALID;
  280.     }
  281.   }
  282.   
  283. #if FTP_DEBUG
  284.   printf("Connecting to %s...\n",adr);
  285. #endif
  286.   
  287.   // connexion
  288.   {
  289.     SOCaddr server;
  290.     int server_size=sizeof(server);
  291.     t_hostent* hp;    
  292.     char * a;
  293.     char _adr[256];
  294.     _adr[0]='\0';
  295.     //T_SOC soc_ctl;
  296.     // effacer structure
  297.     memset(&server, 0, sizeof(server));
  298.     
  299.     // port
  300.     a=strchr(adr,':');    // port
  301.     if (a) {
  302.       sscanf(a+1,"%d",&port);
  303.       strncatbuff(_adr,adr,(int) (a - adr));
  304.     } else
  305.       strcpybuff(_adr,adr);
  306.     
  307.     // rΘcupΘrer adresse rΘsolue
  308.     strcpybuff(back->info,"host name");
  309.     hp = hts_gethostbyname(_adr, &fullhostent_buffer);
  310.     if (hp == NULL) {
  311.       strcpybuff(back->r.msg,"Unable to get server's address");
  312.       // back->status=FTP_STATUS_READY;    // fini
  313.       back->r.statuscode=STATUSCODE_NON_FATAL;
  314.       _HALT_FTP
  315.         return 0;
  316.     }
  317.     _CHECK_HALT_FTP;
  318.     
  319.     // copie adresse
  320.     SOCaddr_copyaddr(server, server_size, hp->h_addr_list[0], hp->h_length);
  321.     // copie adresse pour cnx data
  322.     SOCaddr_copyaddr(server_data, server_data_size, hp->h_addr_list[0], hp->h_length);
  323.     // memcpy(&server.sin_addr, hp->h_addr, hp->h_length);
  324.     
  325.     // crΘer ("attachement") une socket (point d'accΦs) internet,en flot
  326.     soc_ctl=socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0);
  327.     if (soc_ctl==INVALID_SOCKET) {
  328.       strcpybuff(back->r.msg,"Unable to create a socket");
  329.       // back->status=FTP_STATUS_READY;    // fini
  330.       back->r.statuscode=STATUSCODE_INVALID;
  331.       _HALT_FTP
  332.         return 0;
  333.     }
  334.  
  335.     SOCaddr_initport(server, port);
  336.     // server.sin_port = htons((unsigned short int) port);
  337.     
  338.     // connexion (bloquante, on est en thread)
  339.     strcpybuff(back->info,"connect");
  340.  
  341. #if HTS_WIN
  342.     if (connect(soc_ctl, (const struct sockaddr FAR *)&server, server_size) != 0) {
  343. #else
  344.       if (connect(soc_ctl, (struct sockaddr *)&server, server_size) == -1) {
  345. #endif
  346.         strcpybuff(back->r.msg,"Unable to connect to the server");
  347.         // back->status=FTP_STATUS_READY;    // fini
  348.         back->r.statuscode=STATUSCODE_INVALID;
  349.         _HALT_FTP
  350.           return 0;
  351. #if HTS_WIN
  352.       }
  353. #else
  354.     }
  355. #endif
  356.     _CHECK_HALT_FTP;
  357.     
  358.     {
  359.       char BIGSTK line[1024];
  360.       // envoi du login
  361.       
  362.       // --USER--
  363.       get_ftp_line(soc_ctl,line,timeout);    // en tΩte
  364.       _CHECK_HALT_FTP;
  365.       
  366.       if (line[0]=='2') {        // ok, connectΘ
  367.         strcpybuff(back->info,"login: user");
  368.         sprintf(line,"USER %s",user);
  369.         send_line(soc_ctl,line);
  370.         get_ftp_line(soc_ctl,line,timeout);
  371.         _CHECK_HALT_FTP;      
  372.         if ((line[0]=='3') || (line[0]=='2')) {
  373.           // --PASS--
  374.           strcpybuff(back->info,"login: pass");
  375.           sprintf(line,"PASS %s",pass);
  376.           send_line(soc_ctl,line);
  377.           get_ftp_line(soc_ctl,line,timeout);
  378.           _CHECK_HALT_FTP;      
  379.           if (line[0]=='2') {  // ok
  380.             send_line(soc_ctl,"TYPE I");
  381.             get_ftp_line(soc_ctl,line,timeout);
  382.             _CHECK_HALT_FTP;      
  383.             if (line[0]=='2') {
  384.               // ok
  385.             } else {
  386.               strcpybuff(back->r.msg,"TYPE I error");
  387.               // back->status=FTP_STATUS_READY;    // fini
  388.               back->r.statuscode=STATUSCODE_INVALID;
  389.             }
  390. #if 0
  391.             // --CWD--
  392.             char* a;
  393.             a=back->url_fil + strlen(back->url_fil)-1;
  394.             while( (a > back->url_fil) && (*a!='/')) a--;
  395.             if (*a == '/') {    // ok repΘrΘ
  396.               char BIGSTK target[1024];
  397.               target[0]='\0';
  398.               strncatbuff(target,back->url_fil,(int) (a - back->url_fil));
  399.               if (strnotempty(target)==0)
  400.                 strcatbuff(target,"/");
  401.               strcpybuff(back->info,"cwd");
  402.               sprintf(line,"CWD %s",target);
  403.               send_line(soc_ctl,line);
  404.               get_ftp_line(soc_ctl,line,timeout);
  405.               _CHECK_HALT_FTP;      
  406.               if (line[0]=='2') {
  407.                 send_line(soc_ctl,"TYPE I");
  408.                 get_ftp_line(soc_ctl,line,timeout);
  409.                 _CHECK_HALT_FTP;      
  410.                 if (line[0]=='2') {
  411.                   // ok..
  412.                 } else {
  413.                   strcpybuff(back->r.msg,"TYPE I error");
  414.                   // back->status=FTP_STATUS_READY;    // fini
  415.                   back->r.statuscode=STATUSCODE_INVALID;
  416.                 }
  417.               } else {
  418.                 sprintf(back->r.msg,"CWD error: %s",linejmp(line));
  419.                 // back->status=FTP_STATUS_READY;    // fini
  420.                 back->r.statuscode=STATUSCODE_INVALID;
  421.               }    // sinon on est prΩts
  422.             } else {
  423.               strcpybuff(back->r.msg,"Unexpected ftp error");
  424.               // back->status=FTP_STATUS_READY;    // fini
  425.               back->r.statuscode=STATUSCODE_INVALID;
  426.             }
  427. #endif
  428.             
  429.           } else {
  430.             sprintf(back->r.msg,"Bad password: %s",linejmp(line));
  431.             // back->status=FTP_STATUS_READY;    // fini
  432.             back->r.statuscode=STATUSCODE_INVALID;
  433.           }
  434.         } else {
  435.           sprintf(back->r.msg,"Bad user name: %s",linejmp(line));
  436.           // back->status=FTP_STATUS_READY;    // fini
  437.           back->r.statuscode=STATUSCODE_INVALID;
  438.         }
  439.       } else {
  440.         sprintf(back->r.msg,"Connection refused: %s",linejmp(line));
  441.         // back->status=FTP_STATUS_READY;    // fini
  442.         back->r.statuscode=STATUSCODE_INVALID;
  443.       }
  444.      
  445.       // ok, si on est prΩts on Θcoute sur un port et on demande la sauce
  446.       if (back->r.statuscode != -1) {
  447.  
  448.         
  449.         //
  450.         // PrΘ-REST
  451.         //
  452. #if FTP_PASV
  453.         if (SOCaddr_getproto(server, server_size) == '1') {
  454.           strcpybuff(back->info,"pasv");
  455.           sprintf(line,"PASV");
  456.           send_line(soc_ctl,line);
  457.           get_ftp_line(soc_ctl,line,timeout);
  458.         } else { /* ipv6 */
  459.           line[0]='\0';
  460.         }
  461.         _CHECK_HALT_FTP;      
  462.         if (line[0]=='2') {
  463.           char *a,*b,*c;
  464.           a=strchr(line,'(');       // exemple: 227 Entering Passive Mode (123,45,67,89,177,27)
  465.           if (a) {
  466.            
  467.             // -- analyse de l'adresse IP et du port --
  468.             a++;
  469.             b=strchr(a,',');
  470.             if (b) b=strchr(b+1,',');
  471.             if (b) b=strchr(b+1,',');
  472.             if (b) b=strchr(b+1,',');
  473.             c=a; while( (c=strchr(c,',')) ) *c='.';        // remplacer , par .
  474.             if (b) *b='\0';
  475.             //
  476.             strcpybuff(adr_ip,a);       // copier adresse ip
  477.             //
  478.             if (b) {
  479.               a=b+1;  // dΘbut du port
  480.               b=strchr(a,'.');
  481.               if (b) {
  482.                 int n1,n2;
  483.                 //
  484.                 *b='\0';
  485.                 b++;
  486.                 c=strchr(b,')');
  487.                 if (c) {
  488.                   *c='\0';
  489.                   if ( (sscanf(a,"%d",&n1)==1) && (sscanf(b,"%d",&n2)==1) && (strlen(adr_ip)<=16)) {
  490.                     port_pasv=n2+(n1<<8);
  491.                   }
  492.                 } else {
  493.                   deletesoc(soc_dat); soc_dat=INVALID_SOCKET;
  494.                 }    // sinon on est prΩts
  495.               }
  496.             }
  497.             // -- fin analyse de l'adresse IP et du port --
  498.           } else {
  499.             sprintf(back->r.msg,"PASV incorrect: %s",linejmp(line));
  500.             // back->status=FTP_STATUS_READY;    // fini
  501.             back->r.statuscode=STATUSCODE_INVALID;
  502.           }    // sinon on est prΩts
  503.         } else {
  504.           /*
  505.             * try epsv (ipv6) *
  506.           */
  507.           strcpybuff(back->info,"pasv");
  508.           sprintf(line,"EPSV");
  509.           send_line(soc_ctl,line);
  510.           get_ftp_line(soc_ctl,line,timeout);
  511.           _CHECK_HALT_FTP;      
  512.           if (line[0]=='2') { /* got it */
  513.             char *a;
  514.             a=strchr(line,'(');       // exemple: 229 Entering Extended Passive Mode (|||6446|)
  515.             if (
  516.               (a != NULL)
  517.               &&
  518.               (*a == '(') 
  519.               && (*(a+1))
  520.               && (*(a+1) == *(a+2)) && (*(a+1) == *(a+3))
  521.               && (isdigit(*(a+4)))
  522.               && (*(a+5))
  523.               ) {
  524.               unsigned int n1 = 0;
  525.               if (sscanf(a+4,"%d",&n1)==1) {
  526.                 if ((n1 < 65535) && (n1 > 0)) {
  527.                   port_pasv=n1;
  528.                 }
  529.               }
  530.             } else {
  531.               sprintf(back->r.msg,"EPSV incorrect: %s",linejmp(line));
  532.               // back->status=FTP_STATUS_READY;    // fini
  533.               back->r.statuscode=STATUSCODE_INVALID;
  534.             }
  535.           } else {
  536.             sprintf(back->r.msg,"PASV/EPSV error: %s",linejmp(line));
  537.             // back->status=FTP_STATUS_READY;    // fini
  538.             back->r.statuscode=STATUSCODE_INVALID;
  539.           }    // sinon on est prΩts
  540.         }
  541. #else
  542.         // rien α faire avant
  543. #endif
  544.           
  545. #if FTP_PASV
  546.         if (port_pasv) {
  547. #endif
  548.           // SIZE
  549.           if (back->r.statuscode != -1) {
  550.             if (!transfer_list) {
  551.               char* ua=unescape_http(ftp_filename);
  552.               if (
  553.                 (strchr(ua, ' '))
  554.                 ||
  555.                 (strchr(ua, '\"'))
  556.                 ||
  557.                 (strchr(ua, '\''))
  558.                 ) {
  559.                 sprintf(line,"SIZE \"%s\"", ua);
  560.               } else {
  561.                 sprintf(line,"SIZE %s", ua);
  562.               }
  563.               
  564.               // SIZE?
  565.               strcpybuff(back->info,"size");
  566.               send_line(soc_ctl,line);
  567.               get_ftp_line(soc_ctl,line,timeout);
  568.               _CHECK_HALT_FTP;      
  569.               if (line[0]=='2') {  // SIZE compris, ALORS tester REST (sinon pas tester: cf probleme des txt.gz decompresses a la volee)
  570.                 char* szstr = strchr(line, ' ');
  571.                 if (szstr) {
  572.                   LLint size = 0;
  573.                   szstr++;
  574.                   if (sscanf(szstr, LLintP, &size) == 1) {
  575.                     back->r.totalsize = size;
  576.                   }
  577.                 }
  578.  
  579.                 // REST?
  580.                 if (fexist(back->url_sav) && (transfer_list==0)) {
  581.                   strcpybuff(back->info,"rest");
  582.                   sprintf(line,"REST "LLintP,(LLint)fsize(back->url_sav));
  583.                   send_line(soc_ctl,line);
  584.                   get_ftp_line(soc_ctl,line,timeout);
  585.                   _CHECK_HALT_FTP;      
  586.                   if ((line[0]=='3') || (line[0]=='2')) {  // ok
  587.                     rest_understood=1;
  588.                   } // sinon tant pis 
  589.                 } 
  590.               }  // sinon tant pis 
  591.             }
  592.           }
  593. #if FTP_PASV
  594.         }
  595. #endif
  596.  
  597.         //
  598.         // Post-REST
  599.         //
  600. #if FTP_PASV
  601.         // Ok, se connecter
  602.         if (port_pasv) {
  603.           SOCaddr server;
  604.           int server_size=sizeof(server);
  605.           t_hostent* hp;    
  606.           // effacer structure
  607.           memset(&server, 0, sizeof(server));
  608.           
  609.           // infos
  610.           strcpybuff(back->info,"resolv");
  611.           
  612.           // rΘsoudre
  613.           if (adr_ip[0]) {
  614.             hp = hts_gethostbyname(adr_ip, &fullhostent_buffer);
  615.             if (hp) {
  616.               SOCaddr_copyaddr(server, server_size, hp->h_addr_list[0], hp->h_length);
  617.             } else {
  618.               server_size=0;
  619.             }
  620.           } else {
  621.             memcpy(&server, &server_data, sizeof(server_data));
  622.             server_size=server_data_size;
  623.           }
  624.           
  625.           // infos
  626.           strcpybuff(back->info,"cnxdata");
  627. #if FTP_DEBUG
  628.           printf("Data: Connecting to %s:%d...\n", adr_ip, port_pasv);
  629. #endif
  630.           if (server_size > 0) {
  631.             // socket
  632.             soc_dat=socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0);
  633.             if (soc_dat != INVALID_SOCKET) {
  634.               // structure: connexion au domaine internet, port 80 (ou autre)
  635.               SOCaddr_initport(server, port_pasv);
  636.               // server.sin_port = htons((unsigned short int) port_pasv);
  637. #if HTS_WIN
  638.               if (connect(soc_dat, (const struct sockaddr FAR *)&server, server_size) == 0) {
  639. #else
  640.               if (connect(soc_dat, (struct sockaddr *)&server, server_size) != -1) {
  641. #endif
  642.                 strcpybuff(back->info,"retr");
  643.                 strcpybuff(line,line_retr);
  644.                 send_line(soc_ctl,line);
  645.                 get_ftp_line(soc_ctl,line,timeout);
  646.                 _CHECK_HALT_FTP;      
  647.                 if (line[0]=='1') {
  648.                   // OK
  649.                 } else {
  650.                   deletesoc(soc_dat); soc_dat=INVALID_SOCKET;
  651.                   //
  652.                   sprintf(back->r.msg,"RETR command errror: %s",linejmp(line));
  653.                   // back->status=FTP_STATUS_READY;    // fini
  654.                   back->r.statuscode=STATUSCODE_INVALID;
  655.                 }    // sinon on est prΩts
  656.               } else {
  657. #if FTP_DEBUG
  658.                 printf("Data: unable to connect\n");
  659. #endif
  660.                 deletesoc(soc_dat); soc_dat=INVALID_SOCKET;
  661.                 //
  662.                 strcpybuff(back->r.msg,"Unable to connect");
  663.                 // back->status=FTP_STATUS_READY;    // fini
  664.                 back->r.statuscode=STATUSCODE_INVALID;
  665.               }    // sinon on est prΩts
  666.             } else {
  667.               strcpybuff(back->r.msg,"Unable to create a socket");
  668.               // back->status=FTP_STATUS_READY;    // fini
  669.               back->r.statuscode=STATUSCODE_INVALID;
  670.             }    // sinon on est prΩts
  671.           } else {
  672.             sprintf(back->r.msg,"Unable to resolve IP %s",adr_ip);
  673.             // back->status=FTP_STATUS_READY;    // fini
  674.             back->r.statuscode=STATUSCODE_INVALID;
  675.           }    // sinon on est prΩts
  676.         } else {
  677.           sprintf(back->r.msg,"PASV incorrect: %s",linejmp(line));
  678.           // back->status=FTP_STATUS_READY;    // fini
  679.           back->r.statuscode=STATUSCODE_INVALID;
  680.         }    // sinon on est prΩts
  681. #else
  682.         //T_SOC soc_servdat;
  683.         strcpybuff(back->info,"listening");
  684.         if ( (soc_servdat = get_datasocket(line)) != INVALID_SOCKET) {
  685.           _CHECK_HALT_FTP;      
  686.           send_line(soc_ctl,line);          // envoi du RETR
  687.           get_ftp_line(soc_ctl,line,timeout);
  688.           _CHECK_HALT_FTP;      
  689.           if (line[0]=='2') {  // ok
  690.             strcpybuff(back->info,"retr");
  691.             strcpybuff(line,line_retr);
  692.             send_line(soc_ctl,line);
  693.             get_ftp_line(soc_ctl,line,timeout);
  694.             _CHECK_HALT_FTP;      
  695.             if (line[0]=='1') {
  696.               //T_SOC soc_dat;
  697.               struct sockaddr dummyaddr;
  698.               int dummylen = sizeof(struct sockaddr);
  699.               if ( (soc_dat=accept(soc_servdat,&dummyaddr,&dummylen)) == INVALID_SOCKET) {
  700.                 strcpybuff(back->r.msg,"Unable to accept connection");
  701.                 // back->status=FTP_STATUS_READY;    // fini
  702.                 back->r.statuscode=STATUSCODE_INVALID;
  703.               }
  704.             } else {
  705.               sprintf(back->r.msg,"RETR command errror: %s",linejmp(line));
  706.               // back->status=FTP_STATUS_READY;    // fini
  707.               back->r.statuscode=STATUSCODE_INVALID;
  708.             }
  709.           } else {
  710.             sprintf(back->r.msg,"PORT command error: %s",linejmp(line));
  711.             // back->status=FTP_STATUS_READY;    // fini
  712.             back->r.statuscode=STATUSCODE_INVALID;
  713.           }
  714. #if HTS_WIN
  715.           closesocket(soc_servdat);
  716. #else
  717.           close(soc_servdat);
  718. #endif
  719.         } else {
  720.           strcpybuff(back->r.msg,"Unable to listen to a port");
  721.           // back->status=FTP_STATUS_READY;    // fini
  722.           back->r.statuscode=STATUSCODE_INVALID;
  723.         }
  724. #endif
  725.         
  726.         //
  727.         // Ok, connexion initiΘe
  728.         //
  729.         if (soc_dat != INVALID_SOCKET) {
  730.           if (rest_understood) {         // REST envoyΘe et comprise
  731.             file_notify(back->url_adr, back->url_fil, back->url_sav, 0, 1, 0);
  732.             back->r.fp = fileappend(back->url_sav);
  733.           } else {
  734.             file_notify(back->url_adr, back->url_fil, back->url_sav, 1, 1, 0);
  735.             back->r.fp = filecreate(back->url_sav);
  736.           }
  737.           strcpybuff(back->info,"receiving");
  738.           if (back->r.fp != NULL) {
  739.             char BIGSTK buff[1024];
  740.             int len=1;
  741.             int read_len=1024;
  742.             //HTS_TOTAL_RECV_CHECK(read_len);         // Diminuer au besoin si trop de donnΘes reτues
  743.             
  744.             while( (len>0) && (!stop_ftp(back)) ) {
  745.               // attendre les donnΘes
  746.               len=1;    // pas d'erreur pour le moment
  747.               switch(wait_socket_receive(soc_dat,timeout)) {
  748.               case -1:
  749.                 strcpybuff(back->r.msg,"FTP read error");
  750.                 // back->status=FTP_STATUS_READY;    // fini
  751.                 back->r.statuscode=STATUSCODE_INVALID;
  752.                 len=0;    // fin
  753.                 break;
  754.               case 0:
  755.                 sprintf(back->r.msg,"Time out (%d)",timeout);
  756.                 // back->status=FTP_STATUS_READY;    // fini
  757.                 back->r.statuscode=STATUSCODE_INVALID;
  758.                 len=0;    // fin
  759.                 break;
  760.               }
  761.               
  762.               // rΘception
  763.               if (len) {
  764.                 len=recv(soc_dat,buff,read_len,0);
  765.                 if (len>0) {
  766.                   back->r.size+=len;
  767.                   HTS_STAT.HTS_TOTAL_RECV+=len; 
  768.                   if (back->r.fp) {
  769.                     if ((INTsys)fwrite(buff,1,(INTsys)len,back->r.fp) != len) {
  770.                       /*
  771.                       int fcheck;
  772.                       if ((fcheck=check_fatal_io_errno())) {
  773.                         opt->state.exit_xh=-1;
  774.                       }
  775.                       */
  776.                       strcpybuff(back->r.msg,"Write error");
  777.                       // back->status=FTP_STATUS_READY;    // fini
  778.                       back->r.statuscode=STATUSCODE_INVALID;
  779.                       len=0;  // error
  780.                     }
  781.                   } else {
  782.                     strcpybuff(back->r.msg,"Unexpected write error");
  783.                     // back->status=FTP_STATUS_READY;    // fini
  784.                     back->r.statuscode=STATUSCODE_INVALID;
  785.                   }
  786.                 } else {        // Erreur ou terminΘ
  787.                   // back->status=FTP_STATUS_READY;    // fini
  788.                   back->r.statuscode=0;
  789.                   if (back->r.totalsize > 0 && back->r.size != back->r.totalsize) {
  790.                     back->r.statuscode=STATUSCODE_INVALID;
  791.                     strcpybuff(back->r.msg,"FTP file incomplete");
  792.                   }
  793.                 }
  794.                 read_len=1024; 
  795.                 //HTS_TOTAL_RECV_CHECK(read_len);         // Diminuer au besoin si trop de donnΘes reτues
  796.               }
  797.             }
  798.             if (back->r.fp) { 
  799.               fclose(back->r.fp); 
  800.               back->r.fp=NULL;
  801.             }
  802.           } else {
  803.             strcpybuff(back->r.msg,"Unable to write file");
  804.             // back->status=FTP_STATUS_READY;    // fini
  805.             back->r.statuscode=STATUSCODE_INVALID;
  806.           }
  807. #if HTS_WIN
  808.           closesocket(soc_dat);
  809. #else
  810.           close(soc_dat);
  811. #endif
  812.           
  813.           // 226 Transfer complete?
  814.           if (back->r.statuscode != -1) {
  815.             if (wait_socket_receive(soc_ctl,timeout_onfly)>0) {
  816.               // rΘcupΘrer 226 transfer complete
  817.               get_ftp_line(soc_ctl,line,timeout);
  818.               if (line[0]=='2') {       // OK
  819.                 strcpybuff(back->r.msg,"OK");
  820.                 // back->status=FTP_STATUS_READY;    // fini
  821.                 back->r.statuscode=200;
  822.               } else {
  823.                 sprintf(back->r.msg,"RETR incorrect: %s",linejmp(line));
  824.                 // back->status=FTP_STATUS_READY;    // fini
  825.                 back->r.statuscode=STATUSCODE_INVALID;
  826.               }
  827.             } else {
  828.               strcpybuff(back->r.msg,"FTP read error");
  829.               // back->status=FTP_STATUS_READY;    // fini
  830.               back->r.statuscode=STATUSCODE_INVALID;
  831.             }
  832.           }
  833.           
  834.         }
  835.         
  836.         
  837.         
  838.       }
  839.       
  840.       
  841.     }
  842.     
  843.     _CHECK_HALT_FTP;
  844.     strcpybuff(back->info,"quit");
  845.     send_line(soc_ctl,"QUIT");    // bye bye
  846.     get_ftp_line(soc_ctl,NULL,timeout);
  847. #if HTS_WIN
  848.     closesocket(soc_ctl);
  849. #else
  850.     close(soc_ctl);
  851. #endif
  852.   }
  853.   
  854.   if (back->r.statuscode!=-1) {
  855.     back->r.statuscode=200;
  856.     strcpybuff(back->r.msg,"OK");
  857.   }
  858.   // back->status=FTP_STATUS_READY;    // fini
  859.   return 0;
  860. }
  861.  
  862.  
  863.  
  864. // ouverture d'un port
  865. T_SOC get_datasocket(char* to_send) {
  866.   T_SOC soc = INVALID_SOCKET;
  867.   char h_loc[256+2];
  868.   
  869.   to_send[0]='\0';
  870.   if (gethostname(h_loc,256)==0) {    // host name
  871.     SOCaddr server;
  872.     int server_size=sizeof(server);
  873.     t_hostent* hp_loc;
  874.     t_fullhostent buffer;
  875.  
  876.     // effacer structure
  877.     memset(&server, 0, sizeof(server));
  878.  
  879.     if ( (hp_loc=vxgethostbyname(h_loc, &buffer)) ) {  // notre host
  880.  
  881.       // copie adresse
  882.       SOCaddr_copyaddr(server, server_size, hp_loc->h_addr_list[0], hp_loc->h_length);
  883.  
  884.       if ( (soc=socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0)) != INVALID_SOCKET) {
  885.  
  886.         if ( bind(soc,(struct sockaddr*) &server, server_size) == 0 ) {
  887.           SOCaddr server2;
  888.           int len;
  889.           len=sizeof(server2);
  890.           // effacer structure
  891.           memset(&server2, 0, sizeof(server2));
  892.           if (getsockname(soc,(struct sockaddr*) &server2, &len) == 0) {
  893.             // *port=ntohs(server.sin_port);  // rΘcupΘrer port
  894.             if (listen(soc,10)>=0) {    // au pif le 10
  895. #if HTS_INET6==0
  896.               unsigned short int a,n1,n2;
  897.               // calculer port
  898.               a  = SOCaddr_sinport(server2);
  899.               n1 = (a & 0xff);
  900.               n2 = ((a>>8) & 0xff);
  901.               {
  902.                 char dots[256+2];
  903.                 char dot[256+2];
  904.                 char* a;
  905.                 SOCaddr_inetntoa(dot, 256, server2, sizeof(server2));
  906.                 //
  907.                 dots[0]='\0';
  908.                 strncatbuff(dots, dot, 128);
  909.                 while( (a=strchr(dots,'.')) ) *a=',';    // virgules!
  910.                 while( (a=strchr(dots,':')) ) *a=',';    // virgules!
  911.                 sprintf(to_send,"PORT %s,%d,%d",dots,n1,n2);  
  912.               }
  913. #else
  914.               /*
  915.                 EPRT |1|132.235.1.2|6275|
  916.                 EPRT |2|1080::8:800:200C:417A|5282|
  917.               */
  918.               {
  919.                 char dot[256+2];
  920.                 SOCaddr_inetntoa(dot, 256, server2, len);
  921.                 sprintf(to_send,"EPRT |%c|%s|%d|", SOCaddr_getproto(server2, len), dot, SOCaddr_sinport(server2));  
  922.               }
  923. #endif
  924.               
  925.             } else {
  926. #if HTS_WIN
  927.               closesocket(soc);
  928. #else
  929.               close(soc);
  930. #endif
  931.               soc=INVALID_SOCKET;
  932.             }
  933.             
  934.             
  935.           } else {
  936. #if HTS_WIN
  937.             closesocket(soc);
  938. #else
  939.             close(soc);
  940. #endif
  941.             soc=INVALID_SOCKET;
  942.           }
  943.           
  944.           
  945.         } else {
  946. #if HTS_WIN
  947.           closesocket(soc);
  948. #else
  949.           close(soc);
  950. #endif
  951.           soc=INVALID_SOCKET;
  952.         }
  953.       }
  954.     }
  955.   }
  956.   
  957.   
  958.   return soc;
  959. }
  960.  
  961. #if FTP_DEBUG
  962. FILE* dd=NULL;
  963. #endif
  964.  
  965. // routines de rΘception/Θmission
  966. // 0 = ERROR
  967. int send_line(T_SOC soc,char* data) {
  968.   char BIGSTK line[1024];
  969.   if (_DEBUG_HEAD) {
  970.     if (ioinfo) {
  971.       fprintf(ioinfo,"---> %s\x0d\x0a",data);
  972.       fflush(ioinfo);
  973.     }
  974.   }
  975. #if FTP_DEBUG
  976.   if (dd == NULL) dd = fopen("toto.txt","w");
  977.   fprintf(dd,"---> %s\x0d\x0a",data); fflush(dd);
  978.   printf("---> %s",data); fflush(stdout);
  979. #endif
  980.   sprintf(line,"%s\x0d\x0a",data);
  981.   if (check_socket_connect(soc) != 1) {
  982. #if FTP_DEBUG
  983.     printf("!SOC WRITE ERROR\n");
  984. #endif
  985.     return 0;    // erreur, plus connectΘ!
  986.   }
  987. #if FTP_DEBUG
  988.   {
  989.     int r = (send(soc,line,strlen(line),0) == (int) strlen(line));
  990.     printf("%s\x0d\x0a",data); fflush(stdout);
  991.     return r;
  992.   }
  993. #else
  994.   return (send(soc,line,strlen(line),0) == (int) strlen(line));
  995. #endif
  996. }
  997.  
  998. int get_ftp_line(T_SOC soc,char* line,int timeout) {
  999.   char BIGSTK data[1024];
  1000.   int i,ok,multiline;
  1001. #if FTP_DEBUG
  1002.   if (dd == NULL) dd = fopen("toto.txt","w");
  1003. #endif
  1004.   
  1005.   data[0]='\0';
  1006.   i=ok=multiline=0; data[3]='\0';
  1007.   do {
  1008.     char b;                        
  1009.     
  1010.     // vΘrifier donnΘes
  1011.     switch(wait_socket_receive(soc,timeout)) {
  1012.     case -1:   // erreur de lecture
  1013.       if (line) strcpybuff(line,"500 *read error");
  1014.       return 0;
  1015.       break;
  1016.     case 0:
  1017.       if (line) sprintf(line,"500 *read timeout (%d)",timeout);
  1018.       return 0;
  1019.       break;
  1020.     }
  1021.     
  1022.     //HTS_TOTAL_RECV_CHECK(dummy);     // Diminuer au besoin si trop de donnΘes reτues
  1023.     switch(recv(soc,&b,1,0)) {
  1024.       //case 0: break;    // pas encore --> erreur (on attend)!
  1025.     case 1:
  1026.       HTS_STAT.HTS_TOTAL_RECV+=1; // compter flux entrant
  1027.       if ((b!=10) && (b!=13))
  1028.         data[i++]=b;
  1029.       break;
  1030.     default:
  1031.       if (line) strcpybuff(line,"500 *read error");
  1032.       return 0; // error
  1033.       break;
  1034.     }
  1035.     if ( ((b==13) || (b==10)) && (i>0) ){    // CR/LF
  1036.       if (
  1037.         (data[3] == '-')
  1038.         ||
  1039.         ((multiline) && (!isdigit((unsigned char)data[0]))) 
  1040.         )
  1041.       {
  1042.         data[3]='\0';
  1043.         i=0;
  1044.         multiline=1;
  1045.       }
  1046.       else
  1047.         ok=1;    // sortir
  1048.     }
  1049.   } while(!ok);
  1050.   data[i++]='\0';
  1051.   
  1052.   if (_DEBUG_HEAD) {
  1053.     if (ioinfo) {
  1054.       fprintf(ioinfo,"<--- %s\x0d\x0a",data);
  1055.       fflush(ioinfo);
  1056.     }
  1057.   }
  1058. #if FTP_DEBUG
  1059.   fprintf(dd,"<--- %s\n",data); fflush(dd);
  1060.   printf("<--- %s\n",data);
  1061. #endif
  1062.   if (line) strcpybuff(line,data);
  1063.   return (strnotempty(data));
  1064. }
  1065.  
  1066. // sauter NNN
  1067. char* linejmp(char* line) {
  1068.   if (strlen(line)>4)
  1069.     return line+4;
  1070.   else
  1071.     return line;
  1072. }
  1073.  
  1074. // test socket:
  1075. // 0 : no data
  1076. // 1 : data detected
  1077. // -1: error
  1078. int check_socket(T_SOC soc) {
  1079.   fd_set fds,fds_e;           // poll structures
  1080.   struct timeval tv;          // structure for select
  1081.   FD_ZERO(&fds);
  1082.   FD_ZERO(&fds_e); 
  1083.   // socket read 
  1084.   FD_SET(soc,&fds);           
  1085.   // socket error
  1086.   FD_SET(soc,&fds_e);
  1087.   tv.tv_sec=0;
  1088.   tv.tv_usec=0;
  1089.   // poll!     
  1090.   select(soc + 1,&fds,NULL,&fds_e,&tv);
  1091.   if (FD_ISSET(soc,&fds_e)) {  // error detected
  1092.     return -1;
  1093.   } else if (FD_ISSET(soc,&fds)) {
  1094.     return 1;
  1095.   }
  1096.   return 0;
  1097. }
  1098. // check if connected
  1099. int check_socket_connect(T_SOC soc) {
  1100.   fd_set fds,fds_e;           // poll structures
  1101.   struct timeval tv;          // structure for select
  1102.   FD_ZERO(&fds);
  1103.   FD_ZERO(&fds_e); 
  1104.   // socket write 
  1105.   FD_SET(soc,&fds);           
  1106.   // socket error
  1107.   FD_SET(soc,&fds_e);
  1108.   tv.tv_sec=0;
  1109.   tv.tv_usec=0;
  1110.   // poll!     
  1111.   select(soc + 1,NULL,&fds,&fds_e,&tv);
  1112.   if (FD_ISSET(soc,&fds_e)) {  // error detected
  1113.     return -1;
  1114.   } else if (FD_ISSET(soc,&fds)) {
  1115.     return 1;
  1116.   }
  1117.   return 0;
  1118. }
  1119. // attendre des donnΘes
  1120. int wait_socket_receive(T_SOC soc,int timeout) {
  1121.   // attendre les donnΘes
  1122.   TStamp ltime=time_local();
  1123.   int r;
  1124. #if FTP_DEBUG
  1125.   printf("\x0dWaiting for data "); fflush(stdout);
  1126. #endif
  1127.   while( (!(r = check_socket(soc))) && ( ((int) ((TStamp) (time_local()-ltime))) < timeout )) {
  1128.     Sleep(100);
  1129. #if FTP_DEBUG
  1130.     printf("."); fflush(stdout);
  1131. #endif
  1132.   }
  1133. #if FTP_DEBUG
  1134.   printf("\x0dreturn: %d\x0d",r); fflush(stdout);
  1135. #endif
  1136.   return r;
  1137. }
  1138.  
  1139.  
  1140. // cancel reτu?
  1141. int stop_ftp(lien_back* back) {
  1142.   if (back->stop_ftp) {
  1143.     strcpybuff(back->r.msg,"Cancelled by User");
  1144.     // back->status=FTP_STATUS_READY;    // fini
  1145.     back->r.statuscode=STATUSCODE_INVALID;
  1146.     return 1;
  1147.   }
  1148.   return 0;
  1149. }
  1150.  
  1151.  
  1152.  
  1153.  
  1154.